package com.xixibaby.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
@Component
public class SpringUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;


    private static final ConcurrentHashMap<String,Object> PROTOTYPE_MAP = new ConcurrentHashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Prototypes.class);
        for (Map.Entry<String, Object> entry : beansWithAnnotation.entrySet()) {
            Class<?>[] interfaces = entry.getValue().getClass().getInterfaces();

            Prototypes annotation = entry.getValue().getClass().getAnnotation(Prototypes.class);
            if(Assert.empty(annotation)){
                annotation = entry.getValue().getClass().getSuperclass().getAnnotation(Prototypes.class);
            }
            String name = null;
            if(Assert.notEmpty(annotation.key()) && !annotation.key().equals(Object.class)){
                name = annotation.key().getName();
            }else{
                name = interfaces[0].getName();
            }
            PROTOTYPE_MAP.put(name + "_" + annotation.value(),entry.getValue());
        }
        log.info(PROTOTYPE_MAP.toString());
        SpringUtil.applicationContext = applicationContext;

    }

    public static ApplicationContext getApplicationContext() {
        assertApplicationContext();
        return applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName) {
        assertApplicationContext();
        return (T) applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> requiredType,int value) {
        assertApplicationContext();
        return (T) PROTOTYPE_MAP.get(requiredType.getName() + "_" + value);
    }

    public static <T> T getBean(Class<T> requiredType) {
        assertApplicationContext();
        try {
            return applicationContext.getBean(requiredType);
        }catch (NoSuchBeanDefinitionException ex){
            return null;
        }
    }


    private static void assertApplicationContext() {
        if (SpringUtil.applicationContext == null) {
            throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!");
        }
    }
}
